﻿using Dapper;
using Microsoft.EntityFrameworkCore;
using SqlKata;
using System.Data;
using System.Data.Common;
using System.Linq.Expressions;
using Zws.Dapper.Interfaces;

namespace Zws.Dapper.Implements
{
    /// <summary>
    /// 通用仓储
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TEntity"></typeparam>
    public class DbCombineRepository<TDbContext, TEntity> : IDbCombineRepository<TDbContext, TEntity>
        where TDbContext : DbContext
        where TEntity : BaseEntity
    {
        private readonly TDbContext _dbContext;
        private readonly DbConnection _dbConnection;
        private readonly IUnitOfWork _unitOfWork;
        private readonly ISqlCompiler _sqlCompiler;
        public DbCombineRepository(TDbContext dbContext,
            IUnitOfWork unitOfWork,
            ISqlCompiler sqlCompiler)
        {
            _dbContext = dbContext;
            _dbConnection = _dbContext.Database.GetDbConnection();
            _unitOfWork = unitOfWork;
            _sqlCompiler = sqlCompiler;
        }


        /// <summary>
        /// 单条插入
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task AddAsync(TEntity entity)
        {
            await _dbContext.Set<TEntity>().AddAsync(entity);
        }
        /// <summary>
        /// 批量插入
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public async Task AddListAsync(List<TEntity> entities)
        {
            await _dbContext.Set<TEntity>().AddRangeAsync(entities);
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="entity"></param>
        public void Update(TEntity entity)
        {
            _dbContext.Set<TEntity>().Update(entity);
        }
        /// <summary>
        /// 查单条
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<TEntity?> FindByIdAsync(string id)
        {
            return await _dbContext.Set<TEntity>().Where(x => x.Id.Equals(id)).FirstOrDefaultAsync();
        }
        public async Task<TEntity?> FindAsync(Expression<Func<TEntity, bool>> condition)
        {
            return await _dbContext.Set<TEntity>().Where(condition).FirstOrDefaultAsync();
        }
        public async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> condition)
        {
            return await _dbContext.Set<TEntity>().Where(condition).AnyAsync();
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public void DeleteSingle(TEntity entity)
        {
            _dbContext.Set<TEntity>().Remove(entity);
        }
        public void DeleteRange(List<TEntity> entities)
        {
            _dbContext.Set<TEntity>().RemoveRange(entities);
        }


        /// <summary>
        /// 批量查,查单个标量值，如总数
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<int> CountAsync(Query query)
        {
            return await _dbConnection.ExecuteScalarAsync<int>(QueryToSql(query).Item1, QueryToSql(query).Item2, _unitOfWork.GetTransAction());
        }


        /// <summary>
        /// 查询单条
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<T?> QuerySingleAsync<T>(Query query) where T : class
        {
            return await _dbConnection.QuerySingleOrDefaultAsync<T>(QueryToSql(query).Item1, QueryToSql(query).Item2, _unitOfWork.GetTransAction());
        }
        /// <summary>
        /// 查询多条
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<List<T>> QueryAsync<T>(Query query) where T : class
        {
            return (await _dbConnection.QueryAsync<T>(QueryToSql(query).Item1, QueryToSql(query).Item2, _unitOfWork.GetTransAction())).ToList();
        }
        public async Task ExecuteAsync(Query query)
        {
            await _dbConnection.ExecuteAsync(QueryToSql(query).Item1, QueryToSql(query).Item2, _unitOfWork.GetTransAction());
        }
        /// <summary>
        /// 获取实体查询对象,配合sqlkata
        /// </summary>
        public Query GenerateSqlQuery()
        {
            var entityType = _dbContext.Model.FindEntityType(typeof(TEntity));
            var tableName = entityType!.GetTableName();
            return new Query(tableName);
        }
        /// <summary>
        /// 查询记录条数
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public Query CountQuery(Func<Query, Query>? condition = null)
        {
            if (condition == null)
                return GenerateSqlQuery().AsCount();
            return condition(GenerateSqlQuery()).AsCount();
        }
        public async Task<int> EntityCountAsync(Func<Query, Query>? condition = null)
        {
            var query = CountQuery(condition);
            return await CountAsync(query);
        }
        public async Task<bool> EntityIsExistAsync(Func<Query, Query>? condition = null)
        {
            return (await EntityCountAsync(condition)) > 0;
        }


        public async Task<TEntity?> EntityQuerySingleAsync(Func<Query, Query>? condition = null, params string[]? columns)
        {
            var query = SelectColumnQuery(condition, columns);
            return await QuerySingleAsync<TEntity>(query);
        }

        public async Task<List<TEntity>> EntityQueryAsync(Func<Query, Query>? condition = null, params string[]? columns)
        {
            var query = SelectColumnQuery(condition, columns);
            return await QueryAsync<TEntity>(query);
        }

        public Query SelectColumnQuery(Func<Query, Query>? condition = null, params string[]? columns)
        {
            var query = GenerateSqlQuery();
            if (columns != null && columns.Length != 0)
                query = GenerateSqlQuery().Select(columns);
            if (condition != null)
                query = condition(query);
            return query;
        }


        public Tuple<string, DynamicParameters?> QueryToSql(Query query)
        {
            return _sqlCompiler.QueryToSql(query);
        }
        public IDbConnection GetConn()
        {
            return _dbConnection;
        }
    }
}
